#ifdef _WIN32
extern "C" __cdecl int SetConsoleOutputCP(unsigned int code_page);
#endif
#include "build.h"
#include "jakt__arguments.h"
#include "jakt__prelude__static_array.h"
namespace Jakt {
namespace build {
ByteString Jakt::build::ParallelExecutionPool::debug_description() const { auto builder = ByteStringBuilder::create();builder.append("ParallelExecutionPool("sv);{
JaktInternal::PrettyPrint::ScopedLevelIncrease increase_indent {};
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("pids: {}, ", pids);
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("completed: {}, ", completed);
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("pid_index: {}, ", pid_index);
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("max_concurrent: {}", max_concurrent);
}
builder.append(")"sv);return builder.to_string(); }
Jakt::build::ParallelExecutionPool Jakt::build::ParallelExecutionPool::create(size_t const max_concurrent) {
{
return Jakt::build::ParallelExecutionPool(Dictionary<size_t, Jakt::jakt__platform__unknown_process::Process>::create_with_entries({}),Dictionary<size_t, Jakt::jakt__platform__unknown_process::ExitPollResult>::create_with_entries({}),static_cast<size_t>(0ULL),max_concurrent);
}
}

ErrorOr<size_t> Jakt::build::ParallelExecutionPool::run(JaktInternal::DynamicArray<ByteString> const args) {
{
if (this->pids.size() >= this->max_concurrent){
TRY((this->wait_for_any_job_to_complete()));
}
Jakt::jakt__platform__unknown_process::Process const process = TRY((Jakt::jakt__platform__unknown_process::start_background_process(args)));
size_t const id = this->pid_index++;
this->pids.set(id,process);
return id;
}
}

JaktInternal::Optional<Jakt::jakt__platform__unknown_process::ExitPollResult> Jakt::build::ParallelExecutionPool::status(size_t const id) const {
{
if (this->completed.contains(id)){
return this->completed[id];
}
return JaktInternal::OptionalNone();
}
}

ErrorOr<void> Jakt::build::ParallelExecutionPool::wait_for_any_job_to_complete() {
{
JaktInternal::Tuple<JaktInternal::Optional<size_t>,Jakt::jakt__platform__unknown_process::ExitPollResult> const finished_pid_finished_status_ = TRY((Jakt::jakt__platform__unknown_process::wait_for_some_set_of_processes_that_at_least_includes(this->pids)));
JaktInternal::Optional<size_t> const finished_pid = finished_pid_finished_status_.template get<0>();
Jakt::jakt__platform__unknown_process::ExitPollResult const finished_status = finished_pid_finished_status_.template get<1>();

JaktInternal::Dictionary<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> pids_to_remove = Dictionary<size_t, Jakt::jakt__platform__unknown_process::ExitPollResult>::create_with_entries({});
if (finished_pid.has_value()){
pids_to_remove.set(finished_pid.value(),finished_status);
}
{
JaktInternal::DictionaryIterator<size_t,Jakt::jakt__platform__unknown_process::Process> _magic = this->pids.iterator();
for (;;){
JaktInternal::Optional<JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::Process>> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::Process> index__process__ = _magic_value.value();
{
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::Process> const jakt__index__process__ = index__process__;
size_t const index = jakt__index__process__.template get<0>();
Jakt::jakt__platform__unknown_process::Process const process = jakt__index__process__.template get<1>();

JaktInternal::Optional<Jakt::jakt__platform__unknown_process::ExitPollResult> const status = ({ Optional<JaktInternal::Optional<Jakt::jakt__platform__unknown_process::ExitPollResult>> __jakt_var_0;
auto __jakt_var_1 = [&]() -> ErrorOr<JaktInternal::Optional<Jakt::jakt__platform__unknown_process::ExitPollResult>> { return Jakt::jakt__platform__unknown_process::poll_process_exit(process); }();
if (__jakt_var_1.is_error()) {{
pids_to_remove.set(index,finished_status);
continue;
}
} else {__jakt_var_0 = __jakt_var_1.release_value();
}
__jakt_var_0.release_value(); });
if (status.has_value()){
pids_to_remove.set(index,status.value());
}
}

}
}

{
JaktInternal::DictionaryIterator<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> _magic = pids_to_remove.iterator();
for (;;){
JaktInternal::Optional<JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult>> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> index__status__ = _magic_value.value();
{
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> const jakt__index__status__ = index__status__;
size_t const index = jakt__index__status__.template get<0>();
Jakt::jakt__platform__unknown_process::ExitPollResult const status = jakt__index__status__.template get<1>();

this->pids.remove(index);
this->completed.set(index,status);
}

}
}

}
return {};
}

ErrorOr<void> Jakt::build::ParallelExecutionPool::wait_for_all_jobs_to_complete() {
{
while (!this->pids.is_empty()){
TRY((this->wait_for_any_job_to_complete()));
}
}
return {};
}

ErrorOr<void> Jakt::build::ParallelExecutionPool::kill_all() {
{
{
JaktInternal::DictionaryIterator<size_t,Jakt::jakt__platform__unknown_process::Process> _magic = this->pids.iterator();
for (;;){
JaktInternal::Optional<JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::Process>> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::Process> ___process__ = _magic_value.value();
{
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::Process> const jakt_____process__ = ___process__;
size_t const _ = jakt_____process__.template get<0>();
Jakt::jakt__platform__unknown_process::Process const process = jakt_____process__.template get<1>();

TRY((Jakt::jakt__platform__unknown_process::forcefully_kill_process(process)));
}

}
}

}
return {};
}

Jakt::build::ParallelExecutionPool::ParallelExecutionPool(JaktInternal::Dictionary<size_t,Jakt::jakt__platform__unknown_process::Process> a_pids, JaktInternal::Dictionary<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> a_completed, size_t a_pid_index, size_t a_max_concurrent): pids(move(a_pids)), completed(move(a_completed)), pid_index(move(a_pid_index)), max_concurrent(move(a_max_concurrent)){}

ByteString Jakt::build::Builder::debug_description() const { auto builder = ByteStringBuilder::create();builder.append("Builder("sv);{
JaktInternal::PrettyPrint::ScopedLevelIncrease increase_indent {};
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("linked_files: {}, ", linked_files);
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("files_to_compile: {}, ", files_to_compile);
JaktInternal::PrettyPrint::must_output_indentation(builder);
builder.appendff("pool: {}", pool);
}
builder.append(")"sv);return builder.to_string(); }
ErrorOr<Jakt::build::Builder> Jakt::build::Builder::for_building(JaktInternal::DynamicArray<ByteString> const files,size_t const max_concurrent) {
{
return Jakt::build::Builder(DynamicArray<ByteString>::create_with({}),files,Jakt::build::ParallelExecutionPool::create(max_concurrent));
}
}

ErrorOr<void> Jakt::build::Builder::build_all(Jakt::jakt__path::Path const binary_dir,Function<ErrorOr<JaktInternal::DynamicArray<ByteString>>(ByteString, ByteString)> const& compiler_invocation) {
{
JaktInternal::Set<size_t> ids = Set<size_t>::create_with_values({});
{
JaktInternal::ArrayIterator<ByteString> _magic = this->files_to_compile.iterator();
for (;;){
JaktInternal::Optional<ByteString> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
ByteString file_name = _magic_value.value();
{
{
JaktInternal::DictionaryIterator<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> _magic = this->pool.completed.iterator();
for (;;){
JaktInternal::Optional<JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult>> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> id__exit_result__ = _magic_value.value();
{
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> const jakt__id__exit_result__ = id__exit_result__;
size_t const id = jakt__id__exit_result__.template get<0>();
Jakt::jakt__platform__unknown_process::ExitPollResult const exit_result = jakt__id__exit_result__.template get<1>();

if (exit_result.exit_code != static_cast<i32>(0)){
warnln(StringView::from_string_literal("Error: Compilation failed"sv));
TRY((this->pool.kill_all()));
return Error::from_errno(static_cast<i32>(1));
}
}

}
}

ByteString const built_object = binary_dir.join(TRY((Jakt::jakt__path::Path::from_string(file_name).replace_extension(ByteString::from_utf8_without_validation("o"sv)))).to_string()).to_string();
this->linked_files.push(built_object);
JaktInternal::DynamicArray<ByteString> const args = TRY((compiler_invocation(binary_dir.join(file_name).to_string(),built_object)));
size_t const id = TRY((this->pool.run(args)));
ids.add(id);
warnln(StringView::from_string_literal("{:c}[2LBuilding: {}/{} ({})"sv),static_cast<i64>(27LL),ids.size(),this->files_to_compile.size(),file_name);
}

}
}

TRY((this->pool.wait_for_all_jobs_to_complete()));
{
JaktInternal::DictionaryIterator<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> _magic = this->pool.completed.iterator();
for (;;){
JaktInternal::Optional<JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult>> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> id__exit_result__ = _magic_value.value();
{
JaktInternal::Tuple<size_t,Jakt::jakt__platform__unknown_process::ExitPollResult> const jakt__id__exit_result__ = id__exit_result__;
size_t const id = jakt__id__exit_result__.template get<0>();
Jakt::jakt__platform__unknown_process::ExitPollResult const exit_result = jakt__id__exit_result__.template get<1>();

if (exit_result.exit_code != static_cast<i32>(0)){
warnln(StringView::from_string_literal("Error: Compilation failed"sv));
return Error::from_errno(static_cast<i32>(1));
}
}

}
}

this->files_to_compile = DynamicArray<ByteString>::create_with({});
}
return {};
}

ErrorOr<void> Jakt::build::Builder::link_into_archive(ByteString const archiver,ByteString const archive_filename,JaktInternal::DynamicArray<ByteString> const extra_arguments) {
{
JaktInternal::DynamicArray<ByteString> args = DynamicArray<ByteString>::create_with({archiver, [&]() -> ByteString { auto __jakt_enum_value = extra_arguments.size();
if (__jakt_enum_value == static_cast<size_t>(0ULL)) {return ByteString::from_utf8_without_validation("cr"sv);}else {return ByteString::from_utf8_without_validation("crT"sv);} 
}(), archive_filename});
{
JaktInternal::ArrayIterator<ByteString> _magic = this->linked_files.iterator();
for (;;){
JaktInternal::Optional<ByteString> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
ByteString file = _magic_value.value();
{
args.push(file);
}

}
}

args.push_values(extra_arguments);
size_t const id = TRY((this->pool.run(args)));
TRY((this->pool.wait_for_all_jobs_to_complete()));
if (this->pool.status(id).value().exit_code != static_cast<i32>(0)){
warnln(StringView::from_string_literal("Error: Linking failed"sv));
return Error::from_errno(static_cast<i32>(1));
}
}
return {};
}

ErrorOr<void> Jakt::build::Builder::link_into_executable(ByteString const cxx_compiler_path,ByteString const output_filename,JaktInternal::DynamicArray<ByteString> const extra_arguments) {
{
JaktInternal::DynamicArray<ByteString> args = DynamicArray<ByteString>::create_with({cxx_compiler_path, ByteString::from_utf8_without_validation("-o"sv), output_filename});
{
JaktInternal::ArrayIterator<ByteString> _magic = this->linked_files.iterator();
for (;;){
JaktInternal::Optional<ByteString> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
ByteString file = _magic_value.value();
{
args.push(file);
}

}
}

{
JaktInternal::ArrayIterator<ByteString> _magic = extra_arguments.iterator();
for (;;){
JaktInternal::Optional<ByteString> const _magic_value = _magic.next();
if (!_magic_value.has_value()){
break;
}
ByteString arg = _magic_value.value();
{
args.push(arg);
}

}
}

size_t const id = TRY((this->pool.run(args)));
TRY((this->pool.wait_for_all_jobs_to_complete()));
if (this->pool.status(id).value().exit_code != static_cast<i32>(0)){
warnln(StringView::from_string_literal("Error: Linking failed"sv));
return Error::from_errno(static_cast<i32>(1));
}
}
return {};
}

Jakt::build::Builder::Builder(JaktInternal::DynamicArray<ByteString> a_linked_files, JaktInternal::DynamicArray<ByteString> a_files_to_compile, Jakt::build::ParallelExecutionPool a_pool): linked_files(move(a_linked_files)), files_to_compile(move(a_files_to_compile)), pool(move(a_pool)){}

}
} // namespace Jakt
